﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Security.Cryptography;
using System.IO;

namespace DusonFramework.Core
{
    public class Encrypt
    {
        private enum Bit
        {
            Bit16,
            Bit32
        }

        #region Base64

        /// <summary>
        /// 对数据进行Base64编码
        /// </summary>
        /// <param name="inputString">数据</param>
        /// <returns>Base64编码数据</returns>
        public static string Base64Encode(string inputString)
        {
            return Base64Encode(inputString, Encoding.UTF8);
        }
        /// <summary>
        /// 对数据进行Base64编码
        /// </summary>
        /// <param name="inputString">数据</param>
        /// <returns>Base64编码数据</returns>
        public static string Base64Encode(string inputString, Encoding encoding)
        {
            byte[] bytes = encoding.GetBytes(inputString);
            return Convert.ToBase64String(bytes);
        }

        /// <summary>
        /// 对数据进行Base64解码
        /// </summary>
        /// <param name="inputString">数据</param>
        /// <returns>Base64解码数据</returns>
        public static string Base64Decode(string inputString)
        {
            return Base64Decode(inputString, Encoding.UTF8);
        }
        /// <summary>
        /// 对数据进行Base64解码
        /// </summary>
        /// <param name="inputString">数据</param>
        /// <returns>Base64解码数据</returns>
        public static string Base64Decode(string inputString, Encoding encoding)
        {
            byte[] bytes = Convert.FromBase64String(inputString);
            return encoding.GetString(bytes);
        }

        #endregion

        #region MD5

        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="encryptString"></param>
        /// <returns></returns>
        public static string MD5Encrypt(string encryptString)
        {
            return MD5Encrypt(encryptString, Encoding.UTF8);
        }
        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="encryptString"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string MD5Encrypt(string encryptString, Encoding encoding)
        {
            return MD5Encrypt(encryptString, Encoding.UTF8, Bit.Bit32);
        }
        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="encryptString"></param>
        /// <returns></returns>
        public static string MD5Encrypt_16(string encryptString)
        {
            return MD5Encrypt(encryptString, Encoding.UTF8, Bit.Bit16);
        }
        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="encryptString"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string MD5Encrypt_16(string encryptString, Encoding encoding)
        {
            return MD5Encrypt(encryptString, Encoding.UTF8, Bit.Bit16);
        }
        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="encryptString"></param>
        /// <param name="encoding"></param>
        /// <param name="bit"></param>
        /// <returns></returns>
        private static string MD5Encrypt(string encryptString, Encoding encoding, Bit bit)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            Byte[] md5Byte = md5.ComputeHash(encoding.GetBytes(encryptString));

            string result = string.Empty;
            if (bit == Bit.Bit16)
                result = BitConverter.ToString(md5Byte, 4, 8);
            else
                result = BitConverter.ToString(md5Byte);

            // 第二种方法：
            //for (int i = 0; i < md5Byte.Length; i++)
            //{
            //    result = result + md5Byte[i].ToString("X");
            //}

            return result.Replace("-", "");
        }

        /// <summary>
        /// 根据文件来计算散列值
        /// </summary>
        /// <param name="filePath">要计算散列值的文件路径</param>
        /// <returns></returns>
        public string GetMD5FromFile(string filePath)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            byte[] hashed = md5.ComputeHash(stream);
            stream.Close();
            return BitConverter.ToString(hashed).Replace("-", "");
        }

        #endregion

        #region AES

        //默认密钥向量
        private static byte[] AESKeys = { 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F };

        public static string AESEncrypt(string encryptString, string encryptKey)
        {
            encryptKey = encryptKey.Length > 32 ? encryptKey.Substring(0, 32) : encryptKey;
            encryptKey = encryptKey.PadRight(32, ' ');

            RijndaelManaged rijndaelProvider = new RijndaelManaged();
            rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32));
            rijndaelProvider.IV = AESKeys;
            ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor();

            byte[] inputData = Encoding.UTF8.GetBytes(encryptString);
            byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length);

            return Convert.ToBase64String(encryptedData);
        }

        public static string AESDecrypt(string decryptString, string decryptKey)
        {
            decryptKey = decryptKey.Length > 32 ? decryptKey.Substring(0, 32) : decryptKey;
            decryptKey = decryptKey.PadRight(32, ' ');

            RijndaelManaged rijndaelProvider = new RijndaelManaged();
            rijndaelProvider.Key = Encoding.UTF8.GetBytes(decryptKey);
            rijndaelProvider.IV = AESKeys;
            ICryptoTransform rijndaelDecrypt = rijndaelProvider.CreateDecryptor();

            byte[] inputData = Convert.FromBase64String(decryptString);
            byte[] decryptedData = rijndaelDecrypt.TransformFinalBlock(inputData, 0, inputData.Length);

            return Encoding.UTF8.GetString(decryptedData);
        }

        #endregion

        #region DES

        /// <summary>
        /// DES加密
        /// </summary>
        /// <param name="input">待加密的字符串</param>
        /// <param name="key">加密密钥</param>
        /// <returns></returns>
        public static string DESEncrypt(string EncryptString, byte[] Key, byte[] IV)
        {
            byte[] inputByteArray = Encoding.UTF8.GetBytes(EncryptString);
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, des.CreateEncryptor(Key, IV), CryptoStreamMode.Write);
            cStream.Write(inputByteArray, 0, inputByteArray.Length);
            cStream.FlushFinalBlock();
            return Convert.ToBase64String(mStream.ToArray());
        }

        /// <summary>
        /// DES解密
        /// </summary>
        /// <param name="input">待解密的字符串</param>
        /// <param name="key">解密密钥,要求为8位,和加密密钥相同</param>
        /// <returns>解密成功返回解密后的字符串,失败返源串</returns>
        public static string DESDecrypt(string DecryptString, byte[] Key, byte[] IV)
        {
            byte[] inputByteArray = Convert.FromBase64String(DecryptString);
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, des.CreateDecryptor(Key, IV), CryptoStreamMode.Write);
            cStream.Write(inputByteArray, 0, inputByteArray.Length);
            cStream.FlushFinalBlock();
            return Encoding.UTF8.GetString(mStream.ToArray());
        }

        //默认密钥向量
        private static byte[] Keys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };

        /// <summary>
        /// DES加密字符串
        /// </summary>
        /// <param name="encryptString">待加密的字符串</param>
        /// <param name="encryptKey">加密密钥,要求为8位</param>
        /// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
        public static string DESEncrypt(string encryptString, string encryptKey)
        {
            //encryptKey = StringOper.GetSubString(encryptKey, 8, "");
            encryptKey = encryptKey.Length > 8 ? encryptKey.Substring(0, 8) : encryptKey;
            encryptKey = encryptKey.PadRight(8, ' ');
            byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
            byte[] rgbIV = Keys;
            byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
            DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
            cStream.Write(inputByteArray, 0, inputByteArray.Length);
            cStream.FlushFinalBlock();
            return Convert.ToBase64String(mStream.ToArray());
        }

        /// <summary>
        /// DES解密字符串
        /// </summary>
        /// <param name="decryptString">待解密的字符串</param>
        /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>
        /// <returns>解密成功返回解密后的字符串,失败返源串</returns>
        public static string DESDecrypt(string decryptString, string decryptKey)
        {
            decryptKey = decryptKey.Length > 8 ? decryptKey.Substring(0, 8) : decryptKey;
            //decryptKey = StringOper.GetSubString(decryptKey, 8, "");
            decryptKey = decryptKey.PadRight(8, ' ');
            byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey);
            byte[] rgbIV = Keys;
            byte[] inputByteArray = Convert.FromBase64String(decryptString);
            DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();

            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
            cStream.Write(inputByteArray, 0, inputByteArray.Length);
            cStream.FlushFinalBlock();
            return Encoding.UTF8.GetString(mStream.ToArray());
        }

        #endregion

        #region RSA

        /// <summary>
        /// RSA加密函数
        /// </summary>
        /// <param name="xmlPublicKey">说明KEY必须是XML的行式,返回的是字符串</param>
        /// <param name="EncryptString"></param>
        /// <returns></returns>
        public string RSAEncrypt(string xmlPublicKey, string EncryptString)
        {
            byte[] PlainTextBArray;
            byte[] CypherTextBArray;
            string Result;
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(xmlPublicKey);
            PlainTextBArray = (new UnicodeEncoding()).GetBytes(EncryptString);
            CypherTextBArray = rsa.Encrypt(PlainTextBArray, false);
            Result = Convert.ToBase64String(CypherTextBArray);
            return Result;
        }

        /// <summary>
        /// RSA解密函数
        /// </summary>
        /// <param name="xmlPrivateKey"></param>
        /// <param name="DecryptString"></param>
        /// <returns></returns>
        public string RSADecrypt(string xmlPrivateKey, string DecryptString)
        {
            byte[] PlainTextBArray;
            byte[] DypherTextBArray;
            string Result;
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(xmlPrivateKey);
            PlainTextBArray = Convert.FromBase64String(DecryptString);
            DypherTextBArray = rsa.Decrypt(PlainTextBArray, false);
            Result = (new UnicodeEncoding()).GetString(DypherTextBArray);
            return Result;
        }

        /// <summary>
        /// 产生RSA的密钥
        /// </summary>
        /// <param name="xmlKeys">私钥</param>
        /// <param name="xmlPublicKey">公钥</param>
        public void RSAKey(out string xmlKeys, out string xmlPublicKey)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            xmlKeys = rsa.ToXmlString(true);
            xmlPublicKey = rsa.ToXmlString(false);
        }

        /// <summary>
        /// 对MD5加密后的密文进行签名
        /// </summary>
        /// <param name="keyPrivate">私钥</param>
        /// <param name="hashbyteSignature">MD5加密后的密文</param>
        /// <returns></returns>
        public static string RSASignatureFormatter(string keyPrivate, string hashbyteSignature)
        {
            byte[] rgbHash = Convert.FromBase64String(hashbyteSignature);
            RSACryptoServiceProvider key = new RSACryptoServiceProvider();
            key.FromXmlString(keyPrivate);
            RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(key);
            formatter.SetHashAlgorithm("MD5");
            byte[] inArray = formatter.CreateSignature(rgbHash);
            return Convert.ToBase64String(inArray);
        }

        /// <summary>
        /// 签名验证
        /// </summary>
        /// <param name="keyPublic">公钥</param>
        /// <param name="hashbyteDeformatter">待验证的用户名</param>
        /// <param name="deformatterData">注册码</param>
        /// <returns></returns>
        public bool RSASignatureDeformatter(string keyPublic, string hashbyteDeformatter, string deformatterData)
        {
            byte[] rgbHash = Convert.FromBase64String(hashbyteDeformatter);
            RSACryptoServiceProvider key = new RSACryptoServiceProvider();
            key.FromXmlString(keyPublic);
            RSAPKCS1SignatureDeformatter deformatter = new RSAPKCS1SignatureDeformatter(key);
            deformatter.SetHashAlgorithm("MD5");
            byte[] rgbSignature = Convert.FromBase64String(deformatterData);
            if (deformatter.VerifySignature(rgbHash, rgbSignature))
                return true;

            return false;
        }

        #endregion
    }

    /// <summary>
    /// 用于数字签名的hash类
    /// </summary>
    public class MACTripleDESEncrypt
    {
        private MACTripleDES mact;
        private string __key = "ksn168ch";
        private byte[] __data = null;
        /// <summary>
        /// 构造函数
        /// </summary>
        public MACTripleDESEncrypt()
        {
            mact = new MACTripleDES();
        }
        /// <summary>
        /// 获取或设置用于数字签名的密钥
        /// </summary>
        public string Key
        {
            get { return this.__key; }
            set
            {
                int keyLength = value.Length;
                int[] keyAllowLengths = new int[] { 8, 16, 24 };
                bool isRight = false;
                foreach (int i in keyAllowLengths)
                {
                    if (keyLength == keyAllowLengths[i])
                    {
                        isRight = true;
                        break;
                    }
                }
                if (!isRight)
                    throw new ApplicationException("用于数字签名的密钥长度必须是8,16,24值之一");
                else
                    this.__key = value;
            }
        }
        /// <summary>
        /// 获取或设置用于数字签名的用户数据
        /// </summary>
        public byte[] Data
        {
            get { return this.__data; }
            set { this.__data = value; }
        }
        /// <summary>
        /// 得到签名后的hash值
        /// </summary>
        /// <returns></returns>
        public string GetHashValue()
        {
            if (this.Data == null)
                throw new Exception("没有设置要进行数字签名的用户" +
                    "数据(property:Data)");
            byte[] key = Encoding.ASCII.GetBytes(this.Key);
            this.mact.Key = key;
            byte[] hash_b = this.mact.ComputeHash(this.mact.ComputeHash(this.Data));
            return Encoding.ASCII.GetString(hash_b);
        }
    }

}
